﻿//using System;
//using System.Collections.Generic;
//using System.Linq;
//using System.Text;
//using System.Windows.Media.Imaging;
//using System.IO;
//using System.Windows.Media;
//using System.Windows;
//using System.Windows.Ink;

//namespace DotNetImage.Util
//{
//    /// <summary>
//    /// A image processing class with various WPF processing functions
//    /// for all kind of bitmaps and canvas. All functions are static.
//    /// </summary>
//    public static class ImageUtil
//    {
//        /// <summary>
//        /// Converts a FrameworkElement object to a BitmapImage.
//        /// </summary>
//        /// <param name="element">A FrameworkElement object, like Image or InkCanvas</param>
//        /// <param name="encoder">A BitmapEncoder for Png, Bmp, Gif, Tiff or Jpeg</param>
//        /// <returns>Returns an encoded BitmapImage.</returns>
//        public static BitmapImage FrameworkElementToBitmapImage(FrameworkElement element, BitmapEncoder encoder)
//        {
//            Encode(element, encoder);    // Encode canvas

//            BitmapImage bitmapImage = new BitmapImage();

//            // Do not put this statement into a using block
//            // since this is a permanent stream source of the image
//            MemoryStream ms = new MemoryStream();

//            // Push the rendered bitmap to it
//            encoder.Save(ms);

//            // Get the bitmap source from the memory stream
//            bitmapImage.BeginInit();
//            bitmapImage.StreamSource = ms;
//            bitmapImage.EndInit();

//            return bitmapImage;
//        }

//        /// <summary>
//        /// Converts a BitmapSource object to a BitmapImage.
//        /// </summary>
//        /// <param name="source">The bitmap source.</param>
//        /// <param name="encoder">A BitmapEncoder for Png, Bmp, Gif, Tiff or Jpeg</param>
//        /// <returns>Returns an encoded BitmapImage.</returns>
//        public static BitmapImage BitmapSourceToBitmapImage(BitmapSource source, BitmapEncoder encoder)
//        {
//            BitmapImage bitmapImage = new BitmapImage();

//            // Do not put this statement into a using block
//            // since this is a permanent stream source of the image
//            MemoryStream ms = new MemoryStream();

//            encoder.Frames.Add(BitmapFrame.Create(source));
//            encoder.Save(ms);

//            // Get the bitmap source from the memory stream
//            bitmapImage.BeginInit();
//            bitmapImage.StreamSource = ms;
//            bitmapImage.EndInit();

//            return bitmapImage;
//        }

//        /// <summary>
//        /// Saves a FrameworkElement object permanently to a image file.
//        /// </summary>
//        /// <param name="element">A FrameworkElement object, like Image or InkCanvas</param>
//        /// <param name="uri">A relative or absolute Uri for the file path</param>
//        /// <param name="encoder">A BitmapEncoder for Png, Bmp, Gif, Tiff or Jpeg</param>
//        public static void Save(FrameworkElement element, Uri uri, BitmapEncoder encoder)
//        {
//            if (uri == null) return;

//            string path = "";

//            if (uri.IsAbsoluteUri)
//                path = uri.LocalPath;
//            else
//                path = uri.OriginalString;

//            Encode(element, encoder);    // Encode canvas

//            // Create a file stream for saving image
//            using (FileStream outStream = new FileStream(path, FileMode.Create))
//            {
//                // Save the data to the stream
//                encoder.Save(outStream);
//            }
//        }

//        /// <summary>
//        /// Converts a bitmap image to a new bitmap with a new pixel format, 
//        /// like Gray8 or Rgb24.
//        /// </summary>
//        /// <param name="bitmapImage">The bitmap image.</param>
//        /// <param name="pixelFormat">A pixel format from the PixelFormats class.</param>
//        /// <returns>Returns a new converted bitmap.</returns>
//        public static FormatConvertedBitmap ConvertImage(BitmapImage bitmapImage, PixelFormat pixelFormat)
//        {
//            // Convert the BitmapSource to a new format.
//            // Use the BitmapImage created above as the source for a new BitmapSource object
//            // which is set to a gray scale format using the FormatConvertedBitmap BitmapSource.                                               
//            // Note: New BitmapSource does not cache. It is always pulled when required.
//            FormatConvertedBitmap formatConvertedBitmap = new FormatConvertedBitmap();

//            // BitmapSource objects like FormatConvertedBitmap can only have their properties
//            // changed within a BeginInit/EndInit block.
//            formatConvertedBitmap.BeginInit();

//            // Use the BitmapSource object defined above as the source for this new 
//            // BitmapSource (chain the BitmapSource objects together).
//            formatConvertedBitmap.Source = bitmapImage;

//            // Set the new format.
//            formatConvertedBitmap.DestinationFormat = pixelFormat;
//            formatConvertedBitmap.EndInit();

//            return formatConvertedBitmap;
//        }

//        /// <summary>
//        /// Retrieve an array with pixels from a BitmapSource. Depending on the
//        /// bitmap color (8-bit grey, 24-bit true color), one or more bytes per pixel
//        /// were stored in the array.
//        /// </summary>
//        /// <remarks>
//        /// This function starts with the first row and the first column. This
//        /// is the upper left side of the image. Then it copies the first
//        /// row, then the second row and so on.
//        /// </remarks>
//        /// <param name="source">The bitmap source.</param>
//        /// <param name="stride">The stride (image width + padbytes).</param>
//        /// <returns>A byte array withe the bitmap pixels.</returns>
//        public static byte[] GetPixels(BitmapSource source, int stride)
//        {
//            int width = source.PixelWidth;

//            int height = source.PixelHeight;

//            byte[] pixels = new byte[height * stride];

//            source.CopyPixels(pixels, stride, 0);

//            return pixels;
//        }

//        /// <summary>
//        /// Crops a image to the new given rectangular.
//        /// </summary>
//        /// <param name="source"></param>
//        /// <param name="rect"></param>
//        /// <returns></returns>
//        public static CroppedBitmap CropImage(BitmapSource source, Int32Rect rect)
//        {
//            return new CroppedBitmap(source, rect);
//        }

//        /// <summary>
//        /// Segments a byte pixelated image. Depending on the level, all
//        /// higher rows and columns are cropped. This method will create a
//        /// rectangle around the segmented object.
//        /// <code>
//        /// Example: Image data with level=255:
//        /// 
//        /// 255, 255, 255, 255, 255, 255, 255, 255,
//        /// 255, 255, 255, 255, 255,  55, 255, 255,       255, 255, 255,  55, 255
//        /// 255, 255,   4,   8, 255,  15, 117, 255,         4,   8, 255,  15, 117,
//        /// 255, 255,   9,  11, 255,   7,  55, 255,   =>    9,  11, 255,   7,  55,
//        /// 255, 255,   5, 255, 255,   0,  25, 255,         5, 255, 255,   0,  25,
//        /// 255, 255,  14,   2, 255,   3,   1, 255,        14,   2, 255,   3,   1
//        /// 255, 255, 255, 255, 255, 255, 255, 255
//        /// </code>
//        /// </summary>
//        /// <param name="pixels">A byte pixelated image.</param>
//        /// <param name="stride">The stride (width) of the pixelated image.</param>
//        /// <param name="level">The upper bound, which determines when a row/col gets cropped.</param>
//        /// <param name="newWidth">The new width of the cropped bitmap.</param>
//        /// <param name="newHeight">The new height of the cropped bitmap.</param>
//        /// <exception cref="ArgumentOutOfRangeException">If arguments are invalid.</exception>
//        /// <returns>The new cropped matrix in a linear array.</returns>
//        public static byte[] RectangleSegmentation(byte[] pixels, int stride, int level,
//            out int newWidth, out int newHeight)
//        {
//            if (pixels.Length < 1 || stride < 1)
//            {
//                throw new ArgumentOutOfRangeException();
//            }

//            int columns = stride;
//            int rows = pixels.Length / stride;

//            // Create a matrix[rows, columns]
//            byte[,] matrix = To2dArray(pixels, columns);

//            int yMin = -1, yMax = -1, xMin = -1, xMax = -1;

//            // Compute the boundaries
//            for (int i = 0; i < rows; i++)
//            {
//                if (Enumerable.Range(0, columns).Any(j => matrix[i, j] < level))
//                {
//                    yMin = i;
//                    break;
//                }
//            }

//            for (int i = rows - 1; i >= 0; i--)
//            {
//                if (Enumerable.Range(0, columns).Any(j => matrix[i, j] < level))
//                {
//                    yMax = i;
//                    break;
//                }
//            }

//            for (int i = 0; i < columns; i++)
//            {
//                if (Enumerable.Range(0, rows).Any(j => matrix[j, i] < level))
//                {
//                    xMin = i;
//                    break;
//                }
//            }

//            for (int i = columns - 1; i >= 0; i--)
//            {
//                if (Enumerable.Range(0, rows).Any(j => matrix[j, i] < level))
//                {
//                    xMax = i;
//                    break;
//                }
//            }

//            byte[,] subArray = null;

//            // Check if we have a valid rectangle
//            if (yMin == -1 || yMax == -1 || xMin == -1 || xMax == -1)
//            {
//                subArray = new byte[0, 0];
//            }
//            else
//            {
//                subArray = Sub2dArray(matrix, yMin, yMax, xMin, xMax);
//            }

//            newHeight = subArray.GetLength(0);
//            newWidth = subArray.GetLength(1);

//            return To1dArray(subArray);
//        }

//        /// <summary>
//        /// Resizes a given bitmap to a new size.
//        /// </summary>
//        /// <param name="source">The original bitmap source.</param>
//        /// <param name="width">The width of the new scaled bitmap.</param>
//        /// <param name="height">The height of the new scaled bitmap.</param>
//        /// <returns>A new scaled bitmap.</returns>
//        public static BitmapFrame Resize(BitmapSource source, double width, double height)
//        {
//            Transform scale = new ScaleTransform(width / source.Width, height / source.Height, 0, 0);
//            TransformedBitmap tbBitmap = new TransformedBitmap(source, scale);
//            return BitmapFrame.Create(tbBitmap);
//        }

//        /// <summary>
//        /// Creates a new bitmap from a pixels array.
//        /// </summary>
//        /// <param name="width">The width of the bitmap.</param>
//        /// <param name="height">The height of the bitmap.</param>
//        /// <param name="pixelFormat">The pixel format.</param>
//        /// <param name="palette">The palette.</param>
//        /// <param name="pixels">The 1d-array with all pixels.</param>
//        /// <param name="stride">If stride is not width, the stride.</param>
//        /// <exception cref="ArgumentOutOfRangeException">If arguments are invalid.</exception>
//        /// <returns>The encoded bitmap a a byte array.</returns>
//        public static BitmapSource CreateBitmap(int width, int height, PixelFormat pixelFormat,
//            BitmapPalette palette, Array pixels, int stride)
//        {
//            if (width < 0 || height < 0 || pixels.Length < 1 || stride < 1)
//            {
//                throw new ArgumentOutOfRangeException();
//            }

//            // Creates a new empty image with the pre-defined palette
//            BitmapSource image = BitmapSource.Create(
//                width,
//                height,
//                96,
//                96,
//                pixelFormat,
//                palette,
//                pixels,
//                stride);

//            return image;
//        }

//        /// <summary>
//        /// Retrieves the bytes of a bitmap source.
//        /// </summary>
//        /// <param name="source">The bitmap source.</param>
//        /// <param name="encoder">An encoder, like PngBitmapEncoder.</param>
//        /// <returns>Returns a byte array of the bitmap, which could be saved to a file.</returns>
//        public static byte[] BitmapSourceToBytes(BitmapSource source, BitmapEncoder encoder)
//        {
//            byte[] data = null;

//            using (MemoryStream stream = new MemoryStream())
//            {
//                encoder.Frames.Add(BitmapFrame.Create(source));
//                encoder.Save(stream);
//                data = stream.ToArray();
//            }

//            return data;
//        }

//        /// <summary>
//        /// Saves strokes of an inkcanvas object to file.
//        /// </summary>
//        /// <param name="canvas">The canvas.</param>
//        /// <param name="fileName">File to store.</param>
//        public static void SaveAsStrokes(InkCanvas canvas, string fileName)
//        {
//            using (FileStream outStream = new FileStream(fileName, FileMode.Create))
//            {
//                canvas.Strokes.Save(outStream);
//            }
//        }

//        /// <summary>
//        /// Opens strokes from a givem file.
//        /// </summary>
//        /// <param name="canvas">The ink canvas to fill.</param>
//        /// <param name="fileName">The name of the file.</param>
//        public static void OpenAsStrokes(InkCanvas canvas, string fileName)
//        {
//            using (FileStream inStream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
//            {
//                StrokeCollection strokes = new StrokeCollection(inStream);
//                canvas.Strokes = strokes;
//            }
//        }

//        /// <summary>
//        /// Performs a normalization of the pixels. This method will transform
//        /// the byte[] input values to a new range, like [0..255] to [-0.5..0.5]
//        /// with lower = -0.5 and upper = 0.5. The method returns a double, so
//        /// it's possible to transform into negative and positive floating-point 
//        /// numbers. This is similiar to linear transformation with a
//        /// fixed c2 parameter.
//        /// </summary>
//        /// <param name="pixels">The input greyscale values.</param>
//        /// <param name="lower">The lower bound.</param>
//        /// <param name="upper">The upper bound.</param>
//        /// <exception cref="ArgumentOutOfRangeException">If arguments are invalid.</exception>
//        /// <returns>Returns a new transformed array.</returns>
//        public static double[] Normalize(byte[] pixels, double lower, double upper)
//        {
//            if (upper < lower || Math.Abs(upper - lower) < 256 * Double.Epsilon)
//            {
//                throw new ArgumentOutOfRangeException();
//            }

//            double[] output = new double[pixels.Length];

//            for (int i = 0; i < pixels.Length; i++)
//            {
//                double temp = pixels[i] * ((upper - lower) / 255) + lower; // Transformation
//                if (temp > upper)
//                { // Bound, if we have rounding inaccuracies
//                    temp = upper;
//                }
//                else if (temp < lower)
//                {
//                    temp = lower;
//                }
//                output[i] = temp;
//            }

//            return output;
//        }

//        /// <summary>
//        /// Performs a linear grayscale transformation on 8-bit, stretching
//        /// the contrast of the grey image and shifting the histogram.
//        /// </summary>
//        /// <param name="pixels">The input array.</param>
//        /// <param name="c1">Shifts histogram to right (c1 > 0) or left (0 > c1).</param>
//        /// <param name="c2">Set |c2| > 0 for more contrast (wider histogram) and 0 > |c2| for lower.</param>
//        /// <returns> A new transformed 8-bit greyscale array.</returns>
//        public static byte[] LinearGrayscaleTransformation(byte[] pixels, double c1, double c2)
//        {
//            byte[] output = new byte[pixels.Length];

//            for (int i = 0; i < pixels.Length; i++)
//            {
//                double temp = (pixels[i] + c1) * c2; // Transformation
//                if (temp > 255)
//                { // Bound to 8-bit greyscale
//                    temp = 255;
//                }
//                else if (temp < 0)
//                {
//                    temp = 0;
//                }
//                output[i] = Convert.ToByte(temp);
//            }

//            return output;
//        }

//        /// <summary>
//        /// Calculates the stride. When a image is stored in memory, the memory buffer might 
//        /// contain extra padding bytes after each row of pixels.
//        /// Each pixel takes a given number of bits or bytes to store, b Bytes say, 
//        /// so a row of the image takes width * b Bytes to store and this is the stride – 
//        /// or it would be except for the rule that every row of a bitmap has to start 
//        /// aligned on a 32-bit address boundary. What this means is that every row has 
//        /// to be a multiple of four bytes and the stride is the size of the row after 
//        /// rounding up to be a multiple of four bytes. This is done for speed as the
//        /// processor executes faster if it is working on a 32-bit boundary.
//        /// </summary>
//        /// <param name="width">The image width.</param>
//        /// <param name="bytesPerPixel">Bytes per pixel, like 1 for (8-bit grey).</param>
//        /// <returns>Returns the stride.</returns>
//        /// <see cref="http://msdn.microsoft.com/en-us/library/aa473780%28v=vs.85%29.aspx"/>
//        public static int calcStride(int width, int bytesPerPixel)
//        {
//            switch (bytesPerPixel)
//            {
//                case 0: return 0;
//                case 1: return (width + 3) & ~3;
//                case 3: return (width * 3 + 3) & ~3;
//                case 4: return (width * 4);
//                default:
//                    // Calculate stride
//                    int stride = width * bytesPerPixel;

//                    if (stride % 4 != 0)
//                    {
//                        stride += (4 - (stride % 4));
//                    }

//                    return stride;
//            }
//        }

//        /// <summary>
//        /// Encodes a FrameworkElement object like System.Windows.Controls.InkCanvas
//        /// or System.Windows.Controls.Image with the given encoder. The actual
//        /// size will be the total size of the element.
//        /// </summary>
//        /// <param name="element">A FrameworkElement object, like Image or InkCanvas</param>
//        /// <param name="encoder">A BitmapEncoder for Png, Bmp, Gif, Tiff or Jpeg</param>
//        public static void Encode(FrameworkElement element, BitmapEncoder encoder)
//        {
//            // Bypass a bug in rendering. If margin is set, the image gets cropped.
//            Thickness originalMargin = new Thickness(element.Margin.Left,
//                element.Margin.Top, element.Margin.Right, element.Margin.Bottom);

//            element.Margin = new Thickness(0, 0, 0, 0);

//            // Save current element transform
//            Transform transform = element.LayoutTransform;

//            // Reset current transform (in case it is scaled or rotated)
//            element.LayoutTransform = null;

//            // Get the size of the element
//            Size size = new Size(element.Width, element.Height);

//            // Measure and arrange the element
//            // VERY IMPORTANT
//            element.Measure(size);
//            element.Arrange(new Rect(size));

//            // Create a render bitmap and push the element to it
//            RenderTargetBitmap renderBitmap =
//                new RenderTargetBitmap(
//                    (int)size.Width,
//                    (int)size.Height,
//                    96d,
//                    96d,
//                    PixelFormats.Pbgra32);  // Only supported PixelFormat is Pbgra32

//            renderBitmap.Render(element);

//            // Push the rendered bitmap to it
//            encoder.Frames.Add(BitmapFrame.Create(renderBitmap));

//            // Restore previously saved layout
//            element.LayoutTransform = transform;

//            // Restore margin
//            element.Margin = originalMargin;
//        }

//        #region Private helper methods

//        /// <summary>
//        /// Calculate the euklidian distance.
//        /// </summary>
//        /// <param name="dx">The x-coord</param>
//        /// <param name="dy">The y-coord</param>
//        /// <returns>The distance</returns>
//        private static double Distance(double dx, double dy)
//        {
//            return Math.Sqrt((dx * dx) + (dy * dy));
//        }

//        /// <summary>
//        /// Converts a linear 1d-array to a 2d-array.
//        /// </summary>
//        /// <typeparam name="T">The array data type.</typeparam>
//        /// <param name="source">The 1d-array to convert.</param>
//        /// <param name="width">The width (number of columns) of the 2d-array.</param>
//        /// <returns>A new 2d.array.</returns>
//        private static T[,] To2dArray<T>(T[] source, long width)
//        {
//            long height = source.Length / width;
//            T[,] result = new T[height, width];
//            for (long i = 0; i < height; i++)
//            {
//                for (long j = 0; j < width; j++)
//                {
//                    result[i, j] = source[j + i * width];
//                }
//            }
//            return result;
//        }

//        /// <summary>
//        /// Converts a 2d-array back to a 1d-array.
//        /// </summary>
//        /// <typeparam name="T">The array data type.</typeparam>
//        /// <param name="source">The 2d-array to convert.</param>
//        /// <returns>A new 1d.array.</returns>
//        private static T[] To1dArray<T>(T[,] source)
//        {
//            long height = source.GetLength(0);
//            long width = source.GetLength(1);
//            T[] result = new T[height * width];
//            for (long i = 0; i < height; i++)
//            {
//                for (long j = 0; j < width; j++)
//                {
//                    result[j + i * width] = source[i, j];
//                }
//            }
//            return result;
//        }

//        /// <summary>
//        /// Gets a sub matrix of the given 2d-array, specified
//        /// by the top, bottom, left and right bound.
//        /// </summary>
//        /// <typeparam name="T">The array data type.</typeparam>
//        /// <param name="source">The original 2d-array.</param>
//        /// <param name="i0">Upper bound.</param>
//        /// <param name="i1">Lower bound.</param>
//        /// <param name="j0">Left bound.</param>
//        /// <param name="j1">Right bound.</param>
//        /// <returns>A new sub 2d-array.</returns>
//        private static T[,] Sub2dArray<T>(T[,] source, int i0, int i1, int j0, int j1)
//        {
//            T[,] result = new T[i1 - i0 + 1, j1 - j0 + 1];
//            for (long i = i0; i <= i1; i++)
//            {
//                for (long j = j0; j <= j1; j++)
//                {
//                    result[i - i0, j - j0] = source[i, j];
//                }
//            }
//            return result;
//        }

//        #endregion
//    }
//}
